package com.heima.comment.service.impl;


import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;

import com.heima.aliyun.AliyunGreenTemplate;
import com.heima.comment.Vo.ApCommentVo;
import com.heima.comment.model.dto.CommentLikeDto;
import com.heima.comment.model.dto.CommentListDto;
import com.heima.comment.model.entity.ApComment;
import com.heima.comment.model.entity.ApCommentLike;
import com.heima.comment.service.CommentService;
import com.heima.common.constants.CommentConstant;
import com.heima.feign.api.ApUserFeignClient;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.entity.ApUser;
import com.heima.user.util.AppThreadLocalUtil;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CommentServiceImpl implements CommentService {

    @Resource
    private MongoTemplate mongoTemplate;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private AliyunGreenTemplate aliyunGreenTemplate;

    @Resource
    private ApUserFeignClient apUserFeignClient;

    @Override
    public ResponseResult save(String targetId, String content, Short commentType) {
        //1.检查参数
        if (targetId == null || StringUtils.isEmpty(content)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        if (StringUtils.isNotEmpty(content) && content.length() > 140) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "评论内容不能超过140字");
        }
        //2.判断是否登录
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //3.查询用户信息----- 先从Redis中查询, Redis中不存在再从用户服务查询
//        String user_json = stringRedisTemplate.opsForValue().get("LOGIN_USER_" + user.getId());

//        if (StringUtils.isEmpty(user_json)) {
//            ResponseResult<ApUser> result = userFeignClient.findUserById(user.getId());
//            if (result.getCode() == 200 && result.getData() != null) {
//                user = result.getData();
//                user_json = JSON.toJSONString(user);
//                stringRedisTemplate.opsForValue().set("LOGIN_USER_" + user.getId(), user_json, 2, TimeUnit.HOURS);
//            } else {
//                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "当前登录信息有误");
//            }
//        } else {
//            user = JSON.parseObject(user_json, ApUser.class);
//        }

        //4.安全过滤
        Map<String, String> result = aliyunGreenTemplate.greenTextScan(content);
        if (!"pass".equals(result.get("suggestion"))) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "评论信息违规");
        }

        //查询用户详情
        String key = "USER_LOGIN_" + user.getId();
        String userInfo = stringRedisTemplate.opsForValue().get(key);
        //2.1 缓存中没有用户信息
        if (StringUtils.isEmpty(userInfo)) {
            ResponseResult<ApUser> responseResult = apUserFeignClient.queryById(user.getId());
            if (responseResult.getCode()==200 && responseResult.getData()!=null) {
                 user = responseResult.getData();
                 stringRedisTemplate.opsForValue().set(key,JSON.toJSONString(user),1,TimeUnit.DAYS);
            }else {
                return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
            }
        }else {
            user = JSON.parseObject(userInfo,ApUser.class);
        }

        ApComment apComment = new ApComment();
        apComment.setId(ObjectId.get().toHexString());
        apComment.setContent(content);
        apComment.setCreatedTime(new Date());
        apComment.setImage(user.getImage());
        apComment.setNickName(user.getNicknme());
        apComment.setTargetId(targetId);
        apComment.setLikes(0);
        apComment.setReply(0);
        apComment.setUpdatedTime(new Date());
        apComment.setUserId(user.getId());

        mongoTemplate.insert(apComment);

        //如果是评论回复, 需要更新评论回复数量
        if (CommentConstant.COMMENT_TYPE_COMMENT.equals(commentType)) {
            Query query = Query.query(Criteria.where("id").is(targetId));
            UpdateDefinition updateDefinition = new Update().inc("reply", 1);

            mongoTemplate.updateFirst(query, updateDefinition, ApComment.class);
        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 评论点赞
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentLikeDto dto) {
        //1.检查参数
        if (dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //2.判断是否登录
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //3. 判断评论是否存在
        ApComment comment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
        if (comment == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //4. 点赞操作
        String ker = "COMMENT_LIKE_" + user.getId();
        Boolean isMemer = stringRedisTemplate.opsForSet().isMember(ker, dto.getCommentId());
        //4.1 没有对这条评论点过赞 --- 点赞
        if (isMemer && dto.getOperation() == 1) {
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        //3.2 已经对这条评论点过赞 --- 取消点赞
        if (isMemer && dto.getOperation() == 0) {
            //删除Redis数据库数据
            stringRedisTemplate.opsForSet().remove(ker, dto.getCommentId());
            //删除MongoDB数据
            mongoTemplate.remove(Query.query(Criteria.where("userId").is(user.getId()).and("targetId").is(dto.getCommentId())), ApCommentLike.class);

            //评论表点赞数量 - 1
            Query query = Query.query(Criteria.where("id").is(comment.getId()).and("likes").gt(0));
            UpdateDefinition updateDefinition = new Update().inc("likes", -1);
            mongoTemplate.updateFirst(query, updateDefinition, ApComment.class);
        }
        //3.2 没有对这条评论点过赞 --- 点赞
        if (!isMemer && dto.getOperation() == 0) {
            //保存评论点赞数据到Redis
            stringRedisTemplate.opsForSet().add(ker, dto.getCommentId());
            //保存评论点赞数据到MongoDB
            ApCommentLike commentLike = new ApCommentLike();
            commentLike.setId(ObjectId.get().toHexString());
            commentLike.setTargetId(dto.getCommentId());
            commentLike.setUserId(user.getId().intValue());
            commentLike.setCreatedTime(new Date());

            mongoTemplate.save(commentLike);
            //评论表点赞数量 + 1
            Query query = Query.query(Criteria.where("id").is(comment.getId()));
            UpdateDefinition updateDefinition = new Update().inc("likes", 1);
            mongoTemplate.updateFirst(query, updateDefinition, ApComment.class);
        }
        //查询最新的评论数据
        comment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);

        //5.数据返回
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("like", comment.getLikes());
        return ResponseResult.okResult(resultMap);
    }

    /**
     * 加载评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByArticleId(CommentListDto dto) {
        //1.检查参数
        if (dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        if (dto.getSize() == null || dto.getSize() == 0) {
            dto.setSize(10);
        }
        dto.setSize(Math.min(dto.getSize(), 50));

        //2.按照文章id过滤，设置分页和排序
        Query query = Query.query(Criteria.where("targetId").is(dto.getArticleId()).and("createdTime").lt(dto.getMinDate()))
                .with(Sort.by("createdTime").descending()).limit(dto.getSize());
        List<ApComment> commentList = mongoTemplate.find(query, ApComment.class);
        if (CollectionUtils.isEmpty(commentList)) {
            return ResponseResult.okResult(null);
        }
        //3.数据封装返回
        //3.1 用户未登录 加载数据
        ApUser user = AppThreadLocalUtil.getUser();
        if (user == null) {
            return ResponseResult.okResult(commentList);
        }
        //3.2 用户已登录，加载数据，需要判断当前用户点赞了哪些评论
        //3.2.1 根据评论ID集合查询评论点赞信息  当前登录用户点赞了哪些评论
        String key = "COMMNT_LIKE_" + user.getId();
        Set<String> likes_ids = stringRedisTemplate.opsForSet().members(key);
        //3.2.4 如果没有查询到点赞数据
        if (likes_ids == null) {
            return ResponseResult.okResult(commentList);
        }
        //3.2.4 存在点赞数据  [4,5]
        //遍历评论列表, 找到被当前登录用户点赞的评论, 添加标记
        List<ApCommentVo> result = commentList.stream().map(comment -> {
            ApCommentVo apCommentVo = new ApCommentVo();
            BeanUtils.copyProperties(comment, apCommentVo);
            if (likes_ids.contains(comment.getId())) {
                apCommentVo.setOperation((short) 0);
            }
            return apCommentVo;
        }).collect(Collectors.toList());

        return ResponseResult.okResult(result);
    }

    @Override
    public ResponseResult load(String commentId, Date minDate, Integer size) {
        return null;
    }
}